package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ReportServiceImpl  implements ReportService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserMapper userMapper;//查那个表 找哪个mapper
    /**
     * 根据时间区间 进行营业额统计
     * @param begin  开始时间  2023-09-01
     * @param end   结束时间   2023-09-10
     * @return
     */
    @Override
    public TurnoverReportVO getTurnover(LocalDate begin, LocalDate end) {
        // service 做什么呢？
        log.info("营业额统计...前端要什么 我们就封装什么");
        // do 1 时间区间 以字符串形式 之间,隔开
        // 1.1 定义存储 时间区间 的集合
        List<LocalDate> dateList = new ArrayList<>();
        //1.2 循环 遍历 区间每一天对象 存到 集合中
        dateList.add(begin);
        while(!begin.equals(end)){//不进行添加了
            begin = begin.plusDays(1);//往后加一天
            dateList.add(begin);
        }
        //1.3 dateList 存了每一天日期对象  要的结果是字符串
        String dateListStr = StringUtils.join(dateList, ",");
        // do 2  求出每一天的 营业额 存到 营业额集合中  把集合变成字符串
        // 2.1 定义存储 每日营业额的集合
        List<Double> turnoverList = new ArrayList<>();
        // 2.2 遍历出需要查询的指定天  2023-09-01  2023-09-02
        for (LocalDate localDate : dateList) {
            // 2.3 查询数据库 查询中指定天的营业额 存到 集合中
            // localDate 需要查询的每一天
            int status = Orders.COMPLETED;
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            /*
             传递参数的时
                1:指定参数接收
                 status,beginTime,endTime  可以 写多个参数
                    Double sumByDay(int status, LocalDateTime beginTime, LocalDateTime endTime);
                    sql语句上 #{} 和参数名对应
               2: 将指定参数 封装成 dto 数据传输对象  把三个参数封装到 dto对象中
                     TurnoverDTO    status,beginTime,endTime
                      Double sumByDTO(TurnoverDTO dto);
                     sql语句上   #{} 和属性名对应
               3: 将指定参数 存到 Map集合中  键值对
                   Map  map.put("status",5)  map.put() map.put()
                     Double sumByMap(Map map);
                     sql语句上  #{} 和 map里面的key
             */
//            Double turnover = orderMapper.sumByDay(status,beginTime,endTime);
            // 参数封装到map中
            Map map = new HashMap();
            map.put("status",status);
            map.put("beginTime",beginTime);
            map.put("endTime",endTime);
            Double turnover = orderMapper.sumByMap(map);

            turnover = turnover==null?0.0:turnover;//如果当天没有营业额就是0
            turnoverList.add(turnover);// turnover营业额
        }
        // 2.4 把集合变成字符串
        String turnoverListStr = StringUtils.join(turnoverList, ",");

        TurnoverReportVO reportVO = new TurnoverReportVO();
        reportVO.setDateList(dateListStr);
        reportVO.setTurnoverList(turnoverListStr);
        return reportVO;
    }

    @Override
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        // service 做什么呢？
        log.info("用户统计...前端要什么 我们就封装什么");
        // do 1 时间区间 以字符串形式 之间,隔开
        // 1.1 定义存储 时间区间 的集合
        List<LocalDate> dateList = new ArrayList<>();
        //1.2 循环 遍历 区间每一天对象 存到 集合中
        dateList.add(begin);
        while(!begin.equals(end)){//不进行添加了
            begin = begin.plusDays(1);//往后加一天
            dateList.add(begin);
        }
        //1.3 dateList 存了每一天日期对象  要的结果是字符串
        String dateListStr = StringUtils.join(dateList, ",");


        // 2.1  定义 一个存储 每日新增用户数量的集合
        List<Integer> newUserList = new ArrayList<>();
        // 2.2  定义 每日用户总量 列表集合
        List<Integer> totalUserList = new ArrayList<>();
        for (LocalDate localDate : dateList) {
            // 2.3 查询数据库 查询中指定天的 新增用户数存到 集合中
            // localDate 需要查询的每一天
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            Map map = new HashMap();
            map.put("beginTime",beginTime);
            map.put("endTime",endTime);
            Integer newUser = userMapper.countByMap(map);
            newUserList.add(newUser);

            //  2.4 查询数据库 查询中 截止到指定天的 用户总数存到 集合中
            Map map2 = new HashMap();
            map2.put("endTime",endTime);
            Integer totalUser = userMapper.countByMap(map2);
            totalUserList.add(totalUser);
        }
        String newUserListStr = StringUtils.join(newUserList, ",");
        String totalUserListStr = StringUtils.join(totalUserList, ",");
        //前端要什么 我们给什么
        UserReportVO reportVO = new UserReportVO();
        reportVO.setDateList(dateListStr);
        reportVO.setNewUserList(newUserListStr);
        reportVO.setTotalUserList(totalUserListStr);
        return reportVO;
    }

    /**
     * 订单统计
     *      日期列表
     *      每日订单数
     *      每日有效订单数
     *      区间时间的订单总数
     *      区间时间的有效订单数
     *      区间时间的完成率
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO getOrdersStatistics(LocalDate begin, LocalDate end) {
//        日期列表
        // do 1 时间区间 以字符串形式 之间,隔开
        // 1.1 定义存储 时间区间 的集合
        List<LocalDate> dateList = new ArrayList<>();
        //1.2 循环 遍历 区间每一天对象 存到 集合中
        dateList.add(begin);
        while(!begin.equals(end)){//不进行添加了
            begin = begin.plusDays(1);//往后加一天
            dateList.add(begin);
        }
        //1.3 dateList 存了每一天日期对象  要的结果是字符串
        String dateListStr = StringUtils.join(dateList, ",");
//        每日订单数 --集合--string
        //2.1 定义存储每日订单数的集合
//        每日有效订单数---集合--string
        List<Integer> orderCountList = new ArrayList<>();
        //2.2 定义存储每日有效订单数的集合
        List<Integer> validOrderCountList = new ArrayList<>();
        //   3.1 定义接收区间时间的订单总数的 数值
        Integer totalOrderCount = 0;
       //   3.2 定义接收区间时间的有效订单总数的 数值
        Integer validOrderCount = 0;
        for (LocalDate localDate : dateList) {
            // 2.3 查询数据库 查询中指定天的 新增用户数存到 集合中
            // localDate 需要查询的每一天
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            // 2.4 查询每天的订单数  存到集合中
            Integer orderCount = getOrderCount(null,beginTime,endTime);//当天订单总数
            totalOrderCount+=orderCount;
            orderCountList.add(orderCount);
            // 2.5 查询每天的有效订单数  存到集合中
            int status = Orders.COMPLETED;
            Integer validCount = getOrderCount(status,beginTime,endTime);
            validOrderCount += validCount; // 求每天的订单数的和
            validOrderCountList.add(validCount);
        }
        String orderCountListStr = StringUtils.join(orderCountList, ",");
        String validOrderCountListStr = StringUtils.join(validOrderCountList, ",");

//         区间时间的完成率
       //订单完成率
        Double orderCompletionRate = 0.0;//默认完成率是0.0
        //  有效订单数/订单总数   订单总数是0 不能玩
        if(totalOrderCount!=0){//有订单
            orderCompletionRate = validOrderCount.doubleValue()/totalOrderCount;
        }

        //以终为始
        OrderReportVO orderReportVO = new OrderReportVO();
        orderReportVO.setDateList(dateListStr);//日期列表
        orderReportVO.setOrderCountList(orderCountListStr);//每日订单数
        orderReportVO.setValidOrderCountList(validOrderCountListStr);//每日有效订单数
        orderReportVO.setTotalOrderCount(totalOrderCount);//区间订单总数
        orderReportVO.setValidOrderCount(validOrderCount);//区间有效订单总数
        orderReportVO.setOrderCompletionRate(orderCompletionRate);//订单完成率

        return orderReportVO;
    }

    /**
     *  查询在 begin 日期 到 end 日期之间  销量排行前十
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        //查询销量开始 时间
        LocalDateTime beginTime = LocalDateTime.of(begin,LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end,LocalTime.MAX);

        List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.getSalesTop10(beginTime,endTime);
        // 一个个对象
        // 定义 一个接收 菜品名称的 集合
        List<String> nameList = new ArrayList<>();
        // 定义 一个接收 菜品销量 的 集合
        List<Integer> numberList = new ArrayList<>();

        if(goodsSalesDTOList!=null && goodsSalesDTOList.size()>0){
            for (GoodsSalesDTO goodsSalesDTO : goodsSalesDTOList) {
                //            name 口水鱼   number 2
                nameList.add(goodsSalesDTO.getName());//获取商品名称存到商品名称集合
                numberList.add(goodsSalesDTO.getNumber());//获取商品销量 存到商品销量集合
            }
        }
        // 将集合转换成字符串
        String nameListStr = StringUtils.join(nameList,",");
        String numberListStr = StringUtils.join(numberList,",");

        //以终为始
        SalesTop10ReportVO reportVO = new SalesTop10ReportVO();
        reportVO.setNameList(nameListStr);//前十的 菜品/套餐 名字
        reportVO.setNumberList(numberListStr);//前10 菜品/套餐 销量
        return reportVO;
    }

    @Autowired
    private WorkspaceService workspaceService;
    /**
     *   导入运营数据报表
     * @param response
     */
    @Override
    public void exportBusinessData(HttpServletResponse response) {

        try {
            //1: 读取模板
            InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
            // 专门从 类路径下读取 资源文件
            // 流里面的字节变成 excel文件 ？
            XSSFWorkbook excel = new XSSFWorkbook(in);
            //2: 查询数据 写入模板
            //获取 第一个sheet
            XSSFSheet sheet = excel.getSheetAt(0);

            //3.1:得知道 开始时间 和 结束时间    // 9月25   8月26日
            // 开始时间  今天-30天
            LocalDate begin = LocalDate.now().minusDays(30); // 8月26日
            // 结束时间  今天-1天
            LocalDate end = LocalDate.now().minusDays(1);//9月24日、
            // 第二行 第二列  写入 开始时间至结束时间
            sheet.getRow(1).getCell(1).setCellValue(begin+"至"+end);
            //3.2 概览数据
            // 设置开始时间  结束时间
            LocalDateTime beginTime = LocalDateTime.of(begin,LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(end,LocalTime.MAX);
            BusinessDataVO data30VO = workspaceService.getBusinessData(beginTime, endTime);

            // 第四行 第三列  营业额  第五列 订单完成率  第七列 新增用户数
            sheet.getRow(3).getCell(2).setCellValue(data30VO.getTurnover());
            sheet.getRow(3).getCell(4).setCellValue(data30VO.getOrderCompletionRate());
            sheet.getRow(3).getCell(6).setCellValue(data30VO.getNewUsers());
            // 第五行 第三列 有效订单数  第五列 平均客单价
            sheet.getRow(4).getCell(2).setCellValue(data30VO.getValidOrderCount());
            sheet.getRow(4).getCell(4).setCellValue(data30VO.getUnitPrice());

           //明细数据
            for (int i = 0; i < 30; i++) {
                XSSFRow row = sheet.getRow(7 + i);//第八行 每一行
                // 第八行 到最后一行
                // 第二列开始 日期  营业额  有效订单 订单完成率 平均客单价 新增用户数
                LocalDate thatDay = begin.plusDays(i);// 每天往后+
                row.getCell(1).setCellValue(thatDay.toString());
                // 查询date这一天的 营业额数据
                LocalDateTime thatBegin= LocalDateTime.of(thatDay,LocalTime.MIN);
                LocalDateTime thatEnd = LocalDateTime.of(thatDay,LocalTime.MAX);
                BusinessDataVO thatVo = workspaceService.getBusinessData(thatBegin, thatEnd);
                row.getCell(2).setCellValue(thatVo.getTurnover());
                row.getCell(3).setCellValue(thatVo.getValidOrderCount());
                row.getCell(4).setCellValue(thatVo.getOrderCompletionRate());
                row.getCell(5).setCellValue(thatVo.getUnitPrice());
                row.getCell(6).setCellValue(thatVo.getNewUsers());


            }


            //3: 导出模板
            // 通过response 对象获取字节输出流  通过excel方法写到浏览器上
            ServletOutputStream out = response.getOutputStream();
            excel.write(out);

            //释放资源
            out.flush();
            out.close();
            excel.close();


        } catch (IOException e) {
            System.out.println("您读取模板有问题，它不是excel文件...");
            e.printStackTrace();
        }



    }

    /*
    提取一个方法
       返回值 Integer 查询的数量
       参数列表
           Integer status,LocalDateTime beginTime,LocalDateTime endTime
       将三个参数 存到map里面调用mapper 的countByMap方法 返回结果
     */
    private Integer getOrderCount( Integer status,LocalDateTime beginTime,LocalDateTime endTime ){
        Map map2 = new HashMap();
        map2.put("status",status);//设置有效条件 已完成
        map2.put("beginTime",beginTime);
        map2.put("endTime",endTime);
        Integer count = orderMapper.countByMap(map2);//当前有效订单数
        return count;
    }
}
